﻿using System.Windows.Controls;
using System.Collections.Generic;
using TinyEngine.Core.Services;
using System.Windows;
using TinyEngine.Core;

using TinyEngine.Core.Scene;
using System;
using TinyEngine.Core.Camera;
using TinyEngine.Core.Components;
using TinyEngine.Editor.Extensibility;

namespace TinyEngine.Editor.DefaultPlugins.ProjectExplorer
{
    public partial class ProjectExplorer : UserControl
    {
        Dictionary<string, TreeViewItem> TreeNodes = new Dictionary<string, TreeViewItem>();
        public ProjectExplorer()
        {
            InitializeComponent();
            treeView1.PreviewMouseRightButtonDown += new System.Windows.Input.MouseButtonEventHandler(treeView1_PreviewMouseRightButtonDown);
            EditorSession.Instance.AssetsAdded += new Action(Instance_AssetsAdded);
            EditorSession.Instance.SceneClosed += new Action(Instance_SceneClosed);
            EditorSession.Instance.ProjectClosed += new Action(Instance_SceneClosed);

            Setup();
        }

        void Instance_SceneClosed()
        {
            this.treeView1.Items.Clear();
            TreeNodes.Clear();


            var mnu = Resources["mnuScene"] as MenuItem;
            EditorSession.Instance.MainMenu.Items.Remove(mnu);
        }

        void Instance_AssetsAdded()
        {
            LoadAssets(EditorSession.Instance.sceneManager.ActiveGameScene, TreeNodes["Assets"]);
        }

        void treeView1_PreviewMouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            TreeView tv = (TreeView)sender;
            IInputElement element = tv.InputHitTest(e.GetPosition(tv));
            while (!((element is TreeView) || element == null))
            {
                if (element is TreeViewItem)
                    break;

                if (element is FrameworkElement)
                {
                    FrameworkElement fe = (FrameworkElement)element;
                    element = (IInputElement)(fe.Parent ?? fe.TemplatedParent);
                }
                else
                    break;
            }
            if (element is TreeViewItem)
            {

                TreeViewItem itm = element as TreeViewItem;
                ContextMenu mnu = null;
                if (itm.Header.ToString() == "Assets")
                {
                    mnu = Resources["AssetsContextMenu"] as ContextMenu;
                }
                else
                {
                    mnu = Resources["SceneGraphContextMenu"] as ContextMenu;
                }
                
                treeView1.ContextMenu = mnu;

                element.Focus();
                e.Handled = true;
            }
            
        }

        void Setup()
        {
            EditorSession.Instance.SceneLoaded += new Action<TinyScene>(Instance_SceneLoaded);
            EditorSession.Instance.SceneClosed+=new Action(Instance_SceneClosed);
            AddDefaultRootNodes();
        }

        void Instance_SceneLoaded(TinyScene scene)
        {
            activeScene = scene;
            AddDefaultRootNodes();

            SetupContextMenus();
            LoadSceneGraph(scene, TreeNodes["Scene Graph"]);
            LoadAssets(scene, TreeNodes["Assets"]);
            
            LoadCameras(scene, TreeNodes["Cameras"]);

            var mnu = Resources["mnuScene"] as MenuItem;
            EditorSession.Instance.MainMenu.Items.Add(mnu);
        }

        private void LoadCameras(TinyScene scene, TreeViewItem treeViewItem)
        {
            foreach (var item in scene.Cameras)
            {
                var node = new TreeViewItem()
                {
                    Header = item.GetType().Name,
                    Tag = item
                };
                treeViewItem.Items.Add(node);
            }
        }

        private void AddDefaultRootNodes()
        {
            TreeNodes.Clear();
            treeView1.Items.Clear();
            var node = new TreeViewItem();
            node.Header = "Scene Graph";
            TreeNodes.Add(node.Header.ToString(), node);

            node = new TreeViewItem();
            node.Header = "Templates";
            TreeNodes.Add(node.Header.ToString(), node);

            node = new TreeViewItem();
            node.Header = "Cameras";
            TreeNodes.Add(node.Header.ToString(), node);

            node = new TreeViewItem();
            node.Header = "Assets";
            TreeNodes.Add(node.Header.ToString(), node);

            node = new TreeViewItem();
            node.Header = "Textures";
            TreeNodes.Add(node.Header.ToString(), node);
            TreeNodes["Assets"].Items.Add(node);

            node = new TreeViewItem();
            node.Header = "Fonts";
            TreeNodes.Add(node.Header.ToString(), node);
            TreeNodes["Assets"].Items.Add(node);

            treeView1.Items.Add(TreeNodes["Scene Graph"]);
            treeView1.Items.Add(TreeNodes["Templates"]);
            treeView1.Items.Add(TreeNodes["Cameras"]);
            treeView1.Items.Add(TreeNodes["Assets"]);
        }

        TinyScene activeScene = null;

        private MenuItem CreateAddComponentsMenu()
        {
            MenuItem root = new MenuItem()
            {
                Header = "Add Component"
            };
            var asm = ServiceManager.GetService<AssemblyService>();

            foreach (var item in asm.ComponentTypes)
            {
                var newComponent= new MenuItem()
                {
                    Header = item.Name,
                    Tag = item
                };
                newComponent.Click += new RoutedEventHandler(newComponent_Click);
                root.Items.Add(newComponent);
            }
            return root;
        }

        void newComponent_Click(object sender, RoutedEventArgs e)
        {
            var mnu = sender as MenuItem;

            var type = ((System.Type)mnu.Tag);

            var selectedNode = treeView1.SelectedItem as TreeViewItem;

            if (selectedNode != null && selectedNode.Tag is IEntity)
            {
                //Add as a child of the selected item
                var selectedEntity = selectedNode.Tag as IEntity;

                if (selectedEntity != null)
                {
                    var item = Activator.CreateInstance(type, selectedEntity) as ITinyComponent;
                    
                    selectedEntity.Components.Add(item);
                }
            }
            
            RefreshSceneGraph();
            
        }
        private void SetupContextMenus()
        {
            var asm = ServiceManager.GetService<AssemblyService>();
            var mnuItemContextMenu = Resources["SceneGraphContextMenu"] as ContextMenu;
            var mnuMainSceneMenu = (MenuItem)Resources["mnuScene"];

            var addNode = CreateMenuItem("Add Scene Item");
            var addNode2 = CreateMenuItem("Add Scene Item");

            mnuMainSceneMenu.Items.Add(addNode);
            mnuItemContextMenu.Items.Add(addNode2);

            var closeSceneNode = CreateMenuItem("Close Scene");
 
            closeSceneNode.Click += new RoutedEventHandler(closeSceneNode_Click);
            mnuMainSceneMenu.Items.Add(closeSceneNode);
            


            mnuMainSceneMenu.Items.Add(CreateAddComponentsMenu());
            mnuItemContextMenu.Items.Add(CreateAddComponentsMenu());

            MenuItem mnuDelete=new MenuItem()
            {
                Header = "Delete"
            };
            mnuDelete.Click += new RoutedEventHandler(mnuDelete_Click);
            mnuItemContextMenu.Items.Add(mnuDelete);

            foreach (var item in asm.EntityTypes)
            {
                var newEntity = new MenuItem()
                {
                    Header = item.Name,
                    Tag = item
                };
                newEntity.Click += new RoutedEventHandler(newEntity_Click);
                addNode.Items.Add(newEntity);

                newEntity = new MenuItem()
                {
                    Header = item.Name,
                    Tag = item
                };
                newEntity.Click += new RoutedEventHandler(newEntity_Click);
                
                addNode2.Items.Add(newEntity);
            }
            
        }

        private MenuItem CreateMenuItem(string text)
        {
            var mnu = new MenuItem()
            {
                Header = text
            };
            return mnu;
        }

        void mnuDelete_Click(object sender, RoutedEventArgs e)
        {
            var selectedNode = treeView1.SelectedItem as TreeViewItem;

            var selectedEntity = selectedNode.Tag as IEntity;
            if (selectedEntity == null)
                return;

            var res = MessageBox.Show("Are you sure you want to delete this item?", "Delete entity", MessageBoxButton.YesNo);
            if (res == MessageBoxResult.Yes)
            {
                selectedEntity.SceneOwner.Graph.Remove(selectedEntity);
                RefreshSceneGraph();
            }
        }

        void closeSceneNode_Click(object sender, RoutedEventArgs e)
        {
            EditorSession.Instance.CloseScene();
        }

        void newEntity_Click(object sender, RoutedEventArgs e)
        {
            var mnu = sender as MenuItem;

            var type = ((System.Type)mnu.Tag);

            var selectedNode = treeView1.SelectedItem as TreeViewItem;

            var item = Activator.CreateInstance(type) as IEntity;
            item.Name = "New " + type.Name;
            if (selectedNode != null && selectedNode.Tag is IEntity)
            {
                //Add as a child of the selected item
                var selectedEntity = selectedNode.Tag as IEntity;
                if (selectedEntity != null)
                {
                    selectedEntity.Children.Add(item);
                }
            }
            else
            {
                activeScene.Graph.Entities.Add(item);
            }
            RefreshSceneGraph();
            
        }

        private void RefreshSceneGraph()
        {
            LoadSceneGraph(activeScene, TreeNodes["Scene Graph"]);
        }

        private void LoadAssets(TinyScene scene, TreeViewItem treeNode)
        {
            var node = TreeNodes["Textures"];
            node.Items.Clear();

            var assets = ServiceManager.GetService<AssetLibrary>();
            foreach (var item in assets.Sprites)
            {
                var nd = new TreeViewItem();
                nd.Header = item.Value.Name;
                nd.Tag = item;
                node.Items.Add(nd);
            }
        }

        private void LoadSceneGraph(TinyScene scene, TreeViewItem itm)
        {
            itm.Items.Clear();
            
            foreach (var item in  scene.Graph.Entities)
            {
                AddSceneItemRecursive(item, itm);
            }
        }

        private void AddSceneItemRecursive(TinyEngine.Core.IEntity item, TreeViewItem itm)
        {
            var node = new TreeViewItem();
            node.Header = item.Name;
            node.Tag = item;
            itm.Items.Add(node);

            if (item.Components.Count > 0)
            {
                var compNode = new TreeViewItem()
                {
                    Header = "Components"
                };
                foreach (var c in item.Components)
                {
                    var cNode = new TreeViewItem()
                    {
                        Header = c.GetType().Name
                    };
                    cNode.Tag = c;
                    compNode.Items.Add(cNode);
                }
                node.Items.Add(compNode);
            }

            foreach (var child in item.Children)
            {
                AddSceneItemRecursive(child, node);
            }
        }

        private void DoubleClickTree(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (treeView1.SelectedItem != null)
            {
                var node = treeView1.SelectedItem as TreeViewItem;
                if (node.Tag != null)
                {
                    if (node.Tag is IEntity)
                    {
                        if (node.Tag is ICamera)
                        {
                            ICamera cam = node.Tag as ICamera;
                            EditorSession.Instance.MoveScene(cam.Position);
                        }
                        else
                            EditorSession.LoadEditor(node.Tag as IEntity);
                    }
                }
            }
        }

        private void treeView1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            var item = treeView1.SelectedItem as TreeViewItem;
            if(item!=null)
            {
                if (item.Tag is IEntity)
                {
                    EditorSession.Instance.SetSelectedItem(item.Tag as IEntity);
                }
            }
        }
    }
}
